package com.chenjim.glrecorder.surfacetexture;

import static android.opengl.GLES20.glUniform1i;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.util.Log;

import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.charset.StandardCharsets;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class CameraRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
    /*private static final String VERTEX_SHADER =
            "#version 300 es\n" +
                    "layout (location = 0) in vec4 aPosition;\n" +
                    "layout (location = 1) in vec2 aTexCoord;\n" +
                    "uniform mat4 uTextureMatrix;\n" +
                    "out vec2 vTexCoord;\n" +
                    "void main() {\n" +
                    "    gl_Position = aPosition;\n" +
                    "    vTexCoord = (uTextureMatrix * vec4(aTexCoord, 1.0, 1.0)).xy;\n" +
                    "}\n";

    private static final String FRAGMENT_SHADER =
            "#version 300 es\n" +
                    "#extension GL_OES_EGL_image_external_essl3 : require\n" + // 添加扩展声明
                    "precision mediump float;\n" +
                    "uniform samplerExternalOES sTexture;\n" +
                    "in vec2 vTexCoord;\n" +
                    "out vec4 fragColor;\n" +
                    "void main() {\n" +
                    "    fragColor = texture(sTexture, vTexCoord);\n" +
                    "}\n";*/

    private CameraGLSurfaceView mGLSurfaceView;
    private int mProgram;
    private int mOESTextureId;
    private float[] mTransformMatrix = new float[16];
    private FloatBuffer mVertexBuffer;
    private FloatBuffer mTexCoordBuffer;

    private static final float[] VERTICES = {
            -1.0f, -1.0f, 0.0f,
            1.0f, -1.0f, 0.0f,
            -1.0f, 1.0f, 0.0f,
            1.0f, 1.0f, 0.0f
    };

    private static final float[] TEX_COORDS = {
            0.0f, 0.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f
    };
    private Context context;

    public CameraRenderer(Context context, CameraGLSurfaceView glSurfaceView) {
        mGLSurfaceView = glSurfaceView;
        this.context = context;
        // 初始化顶点缓冲区
        ByteBuffer bb = ByteBuffer.allocateDirect(VERTICES.length * 4);
        bb.order(ByteOrder.nativeOrder());
        mVertexBuffer = bb.asFloatBuffer();
        mVertexBuffer.put(VERTICES);
        mVertexBuffer.position(0);

        // 初始化纹理坐标缓冲区
        bb = ByteBuffer.allocateDirect(TEX_COORDS.length * 4);
        bb.order(ByteOrder.nativeOrder());
        mTexCoordBuffer = bb.asFloatBuffer();
        mTexCoordBuffer.put(TEX_COORDS);
        mTexCoordBuffer.position(0);
    }

    @Override
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        // 生成纹理
        int[] textures = new int[1];
        GLES30.glGenTextures(1, textures, 0);
        mOESTextureId = textures[0];

        // 绑定纹理
        GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mOESTextureId);
        checkGlError("glBindTexture");

        // 设置纹理参数
        GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
        GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
        GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
        GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
        checkGlError("glTexParameter");

        // 创建 SurfaceTexture
        SurfaceTexture oldSurfaceTexture = mGLSurfaceView.getSurfaceTexture();
        if (oldSurfaceTexture != null) {
            oldSurfaceTexture.release();
        }

        SurfaceTexture surfaceTexture = new SurfaceTexture(mOESTextureId);
        surfaceTexture.setOnFrameAvailableListener(this);
        mGLSurfaceView.setSurfaceTexture(surfaceTexture);

        // 创建着色器程序
        try {
            mProgram = createProgram(IOUtils.toString(context.getAssets()
                            .open("surface_texture/vertex_shader.glsl"), StandardCharsets.UTF_8),
                    IOUtils.toString(context.getAssets().open("surface_texture/fragment_shader.glsl"), StandardCharsets.UTF_8));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        if (mProgram == 0) {
            throw new RuntimeException("Failed to create program.");
        }
        checkGlError("createProgram");
    }

    // 错误检查方法
    private void checkGlError(String op) {
        int error;
        while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) {
            Log.e("CameraRenderer", op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
    }

    private int width;
    private int height;


    @Override
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES30.glViewport(0, 0, width, height);
        this.width = width;
        this.height = height;
    }

    @Override
    public void onDrawFrame(GL10 unused) {
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);

        SurfaceTexture surfaceTexture = mGLSurfaceView.getSurfaceTexture();
        if (surfaceTexture == null) {
            return;
        }

        // 更新纹理图像
        synchronized (this) {
            surfaceTexture.updateTexImage();
            surfaceTexture.getTransformMatrix(mTransformMatrix);
        }

        GLES30.glUseProgram(mProgram);
        checkGlError("glUseProgram");

        // 获取并设置变换矩阵
        int uMatrixLocation = GLES30.glGetUniformLocation(mProgram, "uTextureMatrix");
        GLES30.glUniformMatrix4fv(uMatrixLocation, 1, false, mTransformMatrix, 0);

        // 绑定纹理
        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
        GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mOESTextureId);

        // 设置纹理采样器
        int uTextureLocation = GLES30.glGetUniformLocation(mProgram, "uTexture");
        GLES30.glUniform1i(uTextureLocation, 0);

        int mViewportInfoUniform = GLES30.glGetUniformLocation(mProgram, "uViewportInfo");
        int mSuperResolutionUniform = GLES30.glGetUniformLocation(mProgram, "uSuperResolution");

        glUniform1i(mSuperResolutionUniform, 1);

        GLES20.glUniform4f(mViewportInfoUniform, 1f / width, 1f / height, width, height);

        Log.i(this.getClass().getSimpleName().toString(), "width" + width);
        Log.i(this.getClass().getSimpleName().toString(), "mSuperResolutionUniform = " + mSuperResolutionUniform);
        Log.i(this.getClass().getSimpleName().toString(), "mViewportInfoUniform = " + mViewportInfoUniform);
        Log.i(this.getClass().getSimpleName().toString(), "uTextureLocation = " + uTextureLocation);
        Log.i(this.getClass().getSimpleName().toString(), "uTextureMatrix = " + uMatrixLocation);


        // 设置顶点属性
        GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, mVertexBuffer);
        GLES30.glEnableVertexAttribArray(0);
        GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, 0, mTexCoordBuffer);
        GLES30.glEnableVertexAttribArray(1);

        // 绘制
        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);

        // 清理
        GLES30.glDisableVertexAttribArray(0);
        GLES30.glDisableVertexAttribArray(1);
        checkGlError("onDrawFrame");
    }

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        mGLSurfaceView.requestRender();
    }

    private int createProgram(String vertexSource, String fragmentSource) {
        int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            Log.e("CameraRenderer", "Vertex shader compilation failed.");
            return 0;
        }

        int fragmentShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentSource);
        if (fragmentShader == 0) {
            Log.e("CameraRenderer", "Fragment shader compilation failed.");
            return 0;
        }

        int program = GLES30.glCreateProgram();
        if (program == 0) {
            Log.e("CameraRenderer", "Could not create program.");
            return 0;
        }

        GLES30.glAttachShader(program, vertexShader);
        GLES30.glAttachShader(program, fragmentShader);
        GLES30.glLinkProgram(program);

        // 检查链接状态
        int[] linkStatus = new int[1];
        GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0);
        if (linkStatus[0] != GLES30.GL_TRUE) {
            String log = GLES30.glGetProgramInfoLog(program);
            Log.e("CameraRenderer", "Program linking failed: " + log);
            GLES30.glDeleteProgram(program);
            return 0;
        }

        // 删除着色器，已链接到程序中
        GLES30.glDeleteShader(vertexShader);
        GLES30.glDeleteShader(fragmentShader);

        return program;
    }

    private int loadShader(int type, String shaderCode) {
        int shader = GLES30.glCreateShader(type);
        if (shader == 0) {
            Log.e("CameraRenderer", "Could not create shader of type " + type);
            return 0;
        }

        GLES30.glShaderSource(shader, shaderCode);
        GLES30.glCompileShader(shader);

        // 检查编译状态
        int[] compileStatus = new int[1];
        GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
        if (compileStatus[0] == 0) {
            String log = GLES30.glGetShaderInfoLog(shader);
            Log.e("CameraRenderer", "Shader compilation failed: " + log);
            GLES30.glDeleteShader(shader);
            return 0;
        }

        return shader;
    }
}
